#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re
import json
import logging
import urlparse
import settings
from utils.context import ctx

logger = logging.getLogger(__name__)


class RequestHeader(object):

    def __init__(self, headers):
        self.__data = self.__convert(headers)

    def get(self, key, default=None):
        return self.__data.get(key.lower(), default)

    def keys(self):
        return self.__data.keys()

    def values(self):
        return self.__data.values()

    def items(self):
        return self.__data.items()

    def __convert(self, d):
        data = {}
        for key, value in d.items():
            key = key.lower().replace('_', '-')
            data[key] = value
        return data

    def __repr__(self):
        return repr(self.__data)


class Request(object):

    def __init__(self, req):
        self.command = req['method'].upper()
        self.method = req['method'].upper()
        self.scheme = req['scheme'].lower()
        self.server_name = req['server_name']
        self.remote_addr = req['remote_addr']
        self.uri = req['uri']
        self.headers = RequestHeader(req['headers'])
        self.body = req['body'].read()
        self.content_type = req.get('content_type'.lower(), '')
        self.content_length = req.get('content_length'.lower(), 0)
        self.query_string = req.get('query_string'.lower(), '')
        self.query_params = self.__extract_query_param(self.query_string)
        self.data = self.__extract_data(self.body) if self.method in ['POST', 'PUT'] else {}

    def __extract_query_param(self, query_string):
        query_params = urlparse.parse_qs(query_string)
        for key, value in query_params.items():
            if len(value) == 1:
                query_params[key] = value[0]
        return query_params

    def __extract_data(self, entity_body):
        data = {}
        content_type = self.content_type
        if content_type.startswith('application/json'):
            data = json.loads(entity_body)
            return data
        elif content_type.startswith('application/x-www-form-urlencoded'):
            data = urlparse.parse_qs(entity_body)
        else:
            raise ValueError('content-type value is invaild.')
        for key, value in data.items():
            if len(value) == 1:
                data[key] = value[0]
        return data


def pump_response(status, headers=None, body=None):
    if headers is None:
        headers = {
            'Content-Type': 'text/plain'
        }
    if body is None:
        body = str(status)
    return {
        'status': status,
        'headers': headers,
        'body': body
    }


def get_pump_application(urls):
    urls = [(re.compile(pattern), _) for pattern, _ in urls]

    def app(req):
        for prog, func in urls:
            result = prog.match(req['uri'][1:])
            if result:
                try:
                    request = Request(req)
                    request.request_id = request.headers.get(settings.REQUEST_ID_HEADER, '')
                    ctx.request = request
                except Exception as e:
                    return pump_response(400)
                try:
                    response = func(request, **result.groupdict())
                    status = response['code']
                    headers = response['headers']
                    body = response['content']
                except Exception as e:
                    logger.exception('internal server error')
                    return pump_response(500)
                return pump_response(status, headers, body)
        return pump_response(404)
    return app
